package org.efs.openreports.engine.sqlsupport;

import java.io.InputStream;
import java.io.Reader;
import java.math.BigDecimal;
import java.net.URL;
import java.sql.Array;
import java.sql.Blob;
import java.sql.Clob;
import java.sql.Connection;
import java.sql.Date;
import java.sql.NClob;
import java.sql.ParameterMetaData;
import java.sql.PreparedStatement;
import java.sql.Ref;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.RowId;
import java.sql.SQLException;
import java.sql.SQLWarning;
import java.sql.SQLXML;
import java.sql.Time;
import java.sql.Timestamp;
import java.util.Calendar;

import org.apache.log4j.Logger;

public class PreparedStatementWrapper implements PreparedStatement {
    protected static final Logger LOG = Logger.getLogger( PreparedStatementWrapper.class );
    private PreparedStatement delegate;
    private ConnectionWrapper connectionWrapper;
    private static int preparedStatementCount = 0;
    private int preparedStatementNumber;
    private boolean closeWasCalled = false;
    private String sql;

    public boolean closeWasCalled() {
        return closeWasCalled;
    }

    protected void log( String message ) {
        LOG.info( "PreparedStatementWrapper: " + connectionWrapper.getConnectionNumber() + "."
                + getPreparedStatementNumber() + ": " + message );
    }

    protected void logStart( String message ) {
        log( "start: " + message );
    }

    protected void logEnd( String message ) {
        log( "  end: " + message );
    }

    protected void logStart( String message, String sql ) {
        log( "start: " + message, sql );
    }

    protected void logEnd( String message, String sql ) {
        log( "  end: " + message, sql );
    }

    protected void log( String message, String sql ) {
        LOG.info( "PreparedStatementWrapper: " + connectionWrapper.getConnectionNumber() + "."
        // + getPreparedStatementNumber() + ": " + message + "SQL: \n" + sql );
                + getPreparedStatementNumber() + ": " + message );
    }

    private void logException( String message, Exception se ) {
        LOG.error( "PreparedStatementWrapper: " + connectionWrapper.getConnectionNumber() + "."
                + getPreparedStatementNumber() + ": " + message, se );
    }

    private void logException( String message, String sql, Exception se ) {
        LOG.error( "PreparedStatementWrapper: " + connectionWrapper.getConnectionNumber() + "."
        // + getPreparedStatementNumber() + ": " + message + "SQL: \n" + sql, se );
                + getPreparedStatementNumber() + ": " + message, se );
    }

    private int getPreparedStatementNumber() {
        return preparedStatementNumber;
    }

    public PreparedStatementWrapper( ConnectionWrapper connectionWrapper, String sql, PreparedStatement delegate ) {
        this.delegate = delegate;
        this.connectionWrapper = connectionWrapper;
        this.preparedStatementNumber = ++preparedStatementCount;
        this.sql = sql;
        connectionWrapper.add( this );
        log( "Constructor" );
    }

    public void addBatch() throws SQLException {
        log( "addBatch" );
        delegate.addBatch();
    }

    public void addBatch( String sql ) throws SQLException {
        log( "addBatch(String sql): " + sql );
        delegate.addBatch( sql );
    }

    public void cancel() throws SQLException {
        delegate.cancel();
    }

    public void clearBatch() throws SQLException {
        delegate.clearBatch();
    }

    public void clearParameters() throws SQLException {
        delegate.clearParameters();
    }

    public void clearWarnings() throws SQLException {
        delegate.clearWarnings();
    }

    public void close() throws SQLException {
        log( "close(): closing ... " );
        delegate.close();
        closeWasCalled = true;
        log( "close(): closed" );
    }


    public boolean execute() throws SQLException {
        String msg = "execute()";
        logStart( msg, sql );
        try {
            return delegate.execute();
        } catch( SQLException se ) {
            logException( msg, sql, se );
            throw se;
        } finally {
            logEnd( msg, sql );
        }
    }


    public boolean execute( String sql, int autoGeneratedKeys ) throws SQLException {
        String message = "execute(String sql, int autoGeneratedKeys)";
        logStart( message, sql );
        try {
            return delegate.execute( sql, autoGeneratedKeys );
        } catch( SQLException se ) {
            logException( message, sql, se );
            throw se;
        } finally {
            logEnd( message, sql );
        }
    }


    public boolean execute( String sql, int[] columnIndexes ) throws SQLException {
        String message = "execute(String sql, int[] columnIndexes )";
        logStart( message, sql );
        try {
            return delegate.execute( sql, columnIndexes );
        } catch( SQLException se ) {
            logException( message, sql, se );
            throw se;
        } finally {
            logEnd( message, sql );
        }
    }


    public boolean execute( String sql, String[] columnNames ) throws SQLException {
        String message = "execute(String sql, String[] columnNames  )";
        log( message, sql );
        try {
            return delegate.execute( sql, columnNames );
        } catch( SQLException se ) {
            logException( message, sql, se );
            throw se;
        } finally {
            logEnd( message, sql );
        }
    }


    public boolean execute( String sql ) throws SQLException {
        String message = "execute(String sql)";
        log( message, sql );
        try {
            return delegate.execute( sql );
        } catch( SQLException se ) {
            logException( message, sql, se );
            throw se;
        } finally {
            logEnd( message, sql );
        }
    }


    public int[] executeBatch() throws SQLException {
        log( "executeBatch()" );
        try {
            return delegate.executeBatch();
        } catch( SQLException se ) {
            logException( "executeBatch()", se );
            throw se;
        }
    }


    public ResultSet executeQuery() throws SQLException {
        log( "executeQuery()", sql );
        try {
            return delegate.executeQuery();
        } catch( SQLException se ) {
            logException( "executeQuery()", sql, se );
            throw se;
        }
    }


    public ResultSet executeQuery( String sql ) throws SQLException {
        log( "executeQuery(String sql)", sql );
        try {
            return delegate.executeQuery( sql );
        } catch( SQLException se ) {
            logException( "executeQuery(String sql)", sql, se );
            throw se;
        }
    }


    public int executeUpdate() throws SQLException {
        log( "executeUpdate()", sql );
        try {
            return delegate.executeUpdate();
        } catch( SQLException se ) {
            logException( "executeUpdate()", sql, se );
            throw se;
        }
    }


    public int executeUpdate( String sql, int autoGeneratedKeys ) throws SQLException {
        log( "executeUpdate(String sql, int autoGeneratedKeys )", sql );
        try {
            return delegate.executeUpdate( sql, autoGeneratedKeys );
        } catch( SQLException se ) {
            logException( "executeUpdate(String sql, int autoGeneratedKeys)", sql, se );
            throw se;
        }
    }


    public int executeUpdate( String sql, int[] columnIndexes ) throws SQLException {
        log( "executeUpdate(String sql, int[] columnIndexes )", sql );
        try {
            return delegate.executeUpdate( sql, columnIndexes );
        } catch( SQLException se ) {
            logException( "executeUpdate(String sql, int[] columnIndexes)", sql, se );
            throw se;
        }
    }


    public int executeUpdate( String sql, String[] columnNames ) throws SQLException {
        log( "executeUpdate(String sql, String[] columnNames )", sql );
        try {
            return delegate.executeUpdate( sql, columnNames );
        } catch( SQLException se ) {
            logException( "executeUpdate(String sql, String[] columnNames )", sql, se );
            throw se;
        }
    }


    public int executeUpdate( String sql ) throws SQLException {
        log( "executeUpdate(String sql)", sql );
        try {
            return delegate.executeUpdate( sql );
        } catch( SQLException se ) {
            logException( "executeUpdate(String sql)", sql, se );
            throw se;
        }
    }


    public Connection getConnection() throws SQLException {
        return delegate.getConnection();
    }


    public int getFetchDirection() throws SQLException {
        return delegate.getFetchDirection();
    }


    public int getFetchSize() throws SQLException {
        return delegate.getFetchSize();
    }


    public ResultSet getGeneratedKeys() throws SQLException {
        return delegate.getGeneratedKeys();
    }


    public int getMaxFieldSize() throws SQLException {
        return delegate.getMaxFieldSize();
    }


    public int getMaxRows() throws SQLException {
        return delegate.getMaxRows();
    }


    public ResultSetMetaData getMetaData() throws SQLException {
        return delegate.getMetaData();
    }


    public boolean getMoreResults() throws SQLException {
        return delegate.getMoreResults();
    }


    public boolean getMoreResults( int current ) throws SQLException {
        return delegate.getMoreResults( current );
    }


    public ParameterMetaData getParameterMetaData() throws SQLException {
        return delegate.getParameterMetaData();
    }


    public int getQueryTimeout() throws SQLException {
        return delegate.getQueryTimeout();
    }


    public ResultSet getResultSet() throws SQLException {
        return delegate.getResultSet();
    }


    public int getResultSetConcurrency() throws SQLException {
        return delegate.getResultSetConcurrency();
    }


    public int getResultSetHoldability() throws SQLException {
        return delegate.getResultSetHoldability();
    }


    public int getResultSetType() throws SQLException {
        return delegate.getResultSetType();
    }


    public int getUpdateCount() throws SQLException {
        return delegate.getUpdateCount();
    }


    public SQLWarning getWarnings() throws SQLException {
        return delegate.getWarnings();
    }


    public boolean isClosed() throws SQLException {
        return delegate.isClosed();
    }


    public boolean isPoolable() throws SQLException {
        return delegate.isPoolable();
    }


    public boolean isWrapperFor( Class<?> iface ) throws SQLException {
        return delegate.isWrapperFor( iface );
    }


    public void setArray( int parameterIndex, Array x ) throws SQLException {
        delegate.setArray( parameterIndex, x );
    }


    public void setAsciiStream( int parameterIndex, InputStream x, int length ) throws SQLException {
        delegate.setAsciiStream( parameterIndex, x, length );
    }


    public void setAsciiStream( int parameterIndex, InputStream x, long length ) throws SQLException {
        delegate.setAsciiStream( parameterIndex, x, length );
    }


    public void setAsciiStream( int parameterIndex, InputStream x ) throws SQLException {
        delegate.setAsciiStream( parameterIndex, x );
    }


    public void setBigDecimal( int parameterIndex, BigDecimal x ) throws SQLException {
        delegate.setBigDecimal( parameterIndex, x );
    }


    public void setBinaryStream( int parameterIndex, InputStream x, int length ) throws SQLException {
        delegate.setBinaryStream( parameterIndex, x, length );
    }


    public void setBinaryStream( int parameterIndex, InputStream x, long length ) throws SQLException {
        delegate.setBinaryStream( parameterIndex, x, length );
    }


    public void setBinaryStream( int parameterIndex, InputStream x ) throws SQLException {
        delegate.setBinaryStream( parameterIndex, x );
    }


    public void setBlob( int parameterIndex, Blob x ) throws SQLException {
        delegate.setBlob( parameterIndex, x );
    }


    public void setBlob( int parameterIndex, InputStream inputStream, long length ) throws SQLException {
        delegate.setBlob( parameterIndex, inputStream, length );
    }


    public void setBlob( int parameterIndex, InputStream inputStream ) throws SQLException {
        delegate.setBlob( parameterIndex, inputStream );
    }


    public void setBoolean( int parameterIndex, boolean x ) throws SQLException {
        delegate.setBoolean( parameterIndex, x );
    }


    public void setByte( int parameterIndex, byte x ) throws SQLException {
        delegate.setByte( parameterIndex, x );
    }


    public void setBytes( int parameterIndex, byte[] x ) throws SQLException {
        delegate.setBytes( parameterIndex, x );
    }


    public void setCharacterStream( int parameterIndex, Reader reader, int length ) throws SQLException {
        delegate.setCharacterStream( parameterIndex, reader, length );
    }


    public void setCharacterStream( int parameterIndex, Reader reader, long length ) throws SQLException {
        delegate.setCharacterStream( parameterIndex, reader, length );
    }


    public void setCharacterStream( int parameterIndex, Reader reader ) throws SQLException {
        delegate.setCharacterStream( parameterIndex, reader );
    }


    public void setClob( int parameterIndex, Clob x ) throws SQLException {
        delegate.setClob( parameterIndex, x );
    }


    public void setClob( int parameterIndex, Reader reader, long length ) throws SQLException {
        delegate.setClob( parameterIndex, reader, length );
    }


    public void setClob( int parameterIndex, Reader reader ) throws SQLException {
        delegate.setClob( parameterIndex, reader );
    }


    public void setCursorName( String name ) throws SQLException {
        delegate.setCursorName( name );
    }


    public void setDate( int parameterIndex, Date x, Calendar cal ) throws SQLException {
        delegate.setDate( parameterIndex, x, cal );
    }


    public void setDate( int parameterIndex, Date x ) throws SQLException {
        delegate.setDate( parameterIndex, x );
    }


    public void setDouble( int parameterIndex, double x ) throws SQLException {
        delegate.setDouble( parameterIndex, x );
    }


    public void setEscapeProcessing( boolean enable ) throws SQLException {
        delegate.setEscapeProcessing( enable );
    }


    public void setFetchDirection( int direction ) throws SQLException {
        delegate.setFetchDirection( direction );
    }


    public void setFetchSize( int rows ) throws SQLException {
        delegate.setFetchSize( rows );
    }


    public void setFloat( int parameterIndex, float x ) throws SQLException {
        delegate.setFloat( parameterIndex, x );
    }


    public void setInt( int parameterIndex, int x ) throws SQLException {
        delegate.setInt( parameterIndex, x );
    }


    public void setLong( int parameterIndex, long x ) throws SQLException {
        delegate.setLong( parameterIndex, x );
    }


    public void setMaxFieldSize( int max ) throws SQLException {
        delegate.setMaxFieldSize( max );
    }


    public void setMaxRows( int max ) throws SQLException {
        delegate.setMaxRows( max );
    }


    public void setNCharacterStream( int parameterIndex, Reader value, long length ) throws SQLException {
        delegate.setNCharacterStream( parameterIndex, value, length );
    }


    public void setNCharacterStream( int parameterIndex, Reader value ) throws SQLException {
        delegate.setNCharacterStream( parameterIndex, value );
    }


    public void setNClob( int parameterIndex, NClob value ) throws SQLException {
        delegate.setNClob( parameterIndex, value );
    }


    public void setNClob( int parameterIndex, Reader reader, long length ) throws SQLException {
        delegate.setNClob( parameterIndex, reader, length );
    }


    public void setNClob( int parameterIndex, Reader reader ) throws SQLException {
        delegate.setNClob( parameterIndex, reader );
    }


    public void setNString( int parameterIndex, String value ) throws SQLException {
        delegate.setNString( parameterIndex, value );
    }


    public void setNull( int parameterIndex, int sqlType, String typeName ) throws SQLException {
        delegate.setNull( parameterIndex, sqlType, typeName );
    }


    public void setNull( int parameterIndex, int sqlType ) throws SQLException {
        delegate.setNull( parameterIndex, sqlType );
    }


    public void setObject( int parameterIndex, Object x, int targetSqlType, int scaleOrLength ) throws SQLException {
        delegate.setObject( parameterIndex, x, targetSqlType, scaleOrLength );
    }


    public void setObject( int parameterIndex, Object x, int targetSqlType ) throws SQLException {
        delegate.setObject( parameterIndex, x, targetSqlType );
    }


    public void setObject( int parameterIndex, Object x ) throws SQLException {
        delegate.setObject( parameterIndex, x );
    }


    public void setPoolable( boolean poolable ) throws SQLException {
        delegate.setPoolable( poolable );
    }


    public void setQueryTimeout( int seconds ) throws SQLException {
        delegate.setQueryTimeout( seconds );
    }


    public void setRef( int parameterIndex, Ref x ) throws SQLException {
        delegate.setRef( parameterIndex, x );
    }


    public void setRowId( int parameterIndex, RowId x ) throws SQLException {
        delegate.setRowId( parameterIndex, x );
    }


    public void setShort( int parameterIndex, short x ) throws SQLException {
        delegate.setShort( parameterIndex, x );
    }


    public void setSQLXML( int parameterIndex, SQLXML xmlObject ) throws SQLException {
        delegate.setSQLXML( parameterIndex, xmlObject );
    }


    public void setString( int parameterIndex, String x ) throws SQLException {
        delegate.setString( parameterIndex, x );
    }


    public void setTime( int parameterIndex, Time x, Calendar cal ) throws SQLException {
        delegate.setTime( parameterIndex, x, cal );
    }


    public void setTime( int parameterIndex, Time x ) throws SQLException {
        delegate.setTime( parameterIndex, x );
    }


    public void setTimestamp( int parameterIndex, Timestamp x, Calendar cal ) throws SQLException {
        delegate.setTimestamp( parameterIndex, x, cal );
    }


    public void setTimestamp( int parameterIndex, Timestamp x ) throws SQLException {
        delegate.setTimestamp( parameterIndex, x );
    }

    @SuppressWarnings( "deprecation" )

    public void setUnicodeStream( int parameterIndex, InputStream x, int length ) throws SQLException {
        delegate.setUnicodeStream( parameterIndex, x, length );
    }


    public void setURL( int parameterIndex, URL x ) throws SQLException {
        delegate.setURL( parameterIndex, x );
    }


    public <T> T unwrap( Class<T> iface ) throws SQLException {
        return delegate.unwrap( iface );
    }

}
